JavaScript30第三十天要實作的專案是一個打地鼠的小遊戲
Github 檔案位置:30 - Whack A Mole
網站的樣子
可以先看看最後的成果
首先,先選取好今天會操作到的 DOM 元素和變數
const holes = document.querySelectorAll('.hole');
const scoreBoard = document.querySelector('.score');
const moles = document.querySelectorAll('.mole');
let lastHole; // 最後一個地鼠洞
let timeUp = false; // 遊戲進行與否
let score = 0; // 分數
這裡先來寫關於亂數的函式,我們需要一個函式名為 randomTime 決定地鼠的出現時長,以及 randomHole 決定是哪隻地鼠出現
randomHole 的實現主要是依造 holes 的陣列長度做 random,再以此索引去求出值,並紀錄最後出現的地鼠索引值,在隨機出跟上一次相同位置時重新 random
function randomTime(min, max) {
  return Math.round(Math.random() * (max - min) + min);
}
function randomHole(holes) {
  const idx = Math.floor(Math.random() * holes.length);
  const hole = holes[idx];
  if (hole === lastHole) {
    console.log('Ah nah thats the same one bud');
    return randomHole(holes);
  }
  lastHole = hole;
  return hole;
}

再來就是要設定讓隨機到的地鼠出來的函式了,首先以寫好的亂數函式產生出現時長的 time 和地鼠位置的 hole,接著再加上寫好的 CSS class,並在 time 毫秒後移除
function peep() {
  const time = randomTime(200, 1000);
  const hole = randomHole(holes);
  hole.classList.add('up');
  setTimeout(() => {
    hole.classList.remove('up');
    if (!timeUp) peep(); // 遊戲尚未結束因此要繼續執行
  }, time);
}
再來來寫開始的函式 startGame,主要是將遊戲設定初始化,譬如 timeUp、score、scoreBoard 等,並執行 peep 函式,最後以定時器來設定結束時間
function startGame() {
  scoreBoard.textContent = 0;
  timeUp = false;
  score = 0;
  peep();
  setTimeout(() => timeUp = true, 10000)
}
因為在 HTML 已經綁好函式的關係,案下旁邊白色的 Start 按鈕後就會開始了
最後最後,終於要來加上打地鼠的事件啦~
以 forEach 函式幫每隻地鼠加上 click 事件,這裡的 bonk 函式邏輯非常簡單,只需要在觸發事件時移除 CSS class 並加一分更新分數即可
值得一提的是 e.isTrusted 會在以腳本觸發事件時回傳 false,可以讓使用者乖乖玩遊戲 XD
function bonk(e) {
  if(!e.isTrusted) return; // cheater!
  score++;
  this.parentNode.classList.remove('up');
  scoreBoard.textContent = score;
}
moles.forEach(mole => mole.addEventListener('click', bonk));
const holes = document.querySelectorAll('.hole');
const scoreBoard = document.querySelector('.score');
const moles = document.querySelectorAll('.mole');
let lastHole;
let timeUp = false;
let score = 0;
function randomTime(min, max) {
  return Math.round(Math.random() * (max - min) + min);
}
function randomHole(holes) {
  const idx = Math.floor(Math.random() * holes.length);
  const hole = holes[idx];
  if (hole === lastHole) {
    console.log('Ah nah thats the same one bud');
    return randomHole(holes);
  }
  lastHole = hole;
  return hole;
}
function peep() {
  const time = randomTime(1000, 2000);
  const hole = randomHole(holes);
  hole.classList.add('up');
  setTimeout(() => {
    hole.classList.remove('up');
    if (!timeUp) peep();
  }, time);
}
function startGame() {
  scoreBoard.textContent = 0;
  timeUp = false;
  score = 0;
  peep();
  setTimeout(() => timeUp = true, 10000)
}
function bonk(e) {
  if(!e.isTrusted) return; // cheater!
  score++;
  this.parentNode.classList.remove('up');
  scoreBoard.textContent = score;
}
moles.forEach(mole => mole.addEventListener('click', bonk));
以上是第三十天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<
Make a Whack A Mole Game with Vanilla JS - #JavaScript30 30/30
[ Alex 宅幹嘛 ] ?? 深入淺出 Javascript30 快速導覽 | Day 30:Whack A Mole
MDN Web Docs